package org.javahispano.javacup.tacticas.tacticas_aceptadas.elepanderevo;

import org.javahispano.javacup.modelo.engine.SituacionPartido;
import org.javahispano.javacup.modelo.util.Posicion;
import org.javahispano.javacup.modelo.util.Constantes;
import org.javahispano.javacup.modelo.TacticaDetalle;
import org.javahispano.javacup.modelo.JugadorDetalle;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.comando.Comando;
import org.javahispano.javacup.modelo.comando.ComandoIrA;
import org.javahispano.javacup.modelo.comando.ComandoGolpearBalon;
import org.javahispano.javacup.render.EstiloUniforme;
import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import org.javahispano.javacup.modelo.*;
import java.util.List;
import java.util.Random;

public class ElepanderEvo implements Tactica {

    Posicion alineacion1[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-22.11188811188811, -22.805429864253394),
        new Posicion(0.2595419847328244, -31.082089552238806),
        new Posicion(21.636363636363637, -23.042986425339365),
        new Posicion(8.797202797202797, -4.98868778280543),
        new Posicion(-9.272727272727272, -5.463800904977376),
        new Posicion(-25.44055944055944, 6.651583710407239),
        new Posicion(23.062937062937063, 6.176470588235294),
        new Posicion(-14.274809160305344, 30.559701492537314),
        new Posicion(-0.951048951048951, 23.993212669683256),
        new Posicion(12.717557251908397, 29.51492537313433)
    };
    Posicion alineacion2[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-11.16030534351145, -31.082089552238806),
        new Posicion(11.16030534351145, -31.6044776119403),
        new Posicion(22.825174825174827, -22.092760180995477),
        new Posicion(-25.916083916083913, -21.142533936651585),
        new Posicion(15.216783216783217, -11.877828054298643),
        new Posicion(-2.8531468531468533, -14.728506787330318),
        new Posicion(9.272727272727272, -3.088235294117647),
        new Posicion(-19.97202797202797, -8.552036199095022),
        new Posicion(-0.23776223776223776, -0.47511312217194573),
        new Posicion(-3.5664335664335667, -1.6628959276018098)
    };
    Posicion alineacion3[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-11.16030534351145, -31.082089552238806),
        new Posicion(11.16030534351145, -31.6044776119403),
        new Posicion(24.727272727272727, -19.004524886877828),
        new Posicion(-29.32824427480916, -21.67910447761194),
        new Posicion(-0.23776223776223776, -19.95475113122172),
        new Posicion(-20.20979020979021, -11.402714932126697),
        new Posicion(19.734265734265733, -8.552036199095022),
        new Posicion(-0.4755244755244755, -9.739819004524888),
        new Posicion(-19.020979020979023, -0.47511312217194573),
        new Posicion(13.552447552447552, -0.23755656108597287)
    };
    Posicion alineacion4[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-11.16030534351145, -31.082089552238806),
        new Posicion(11.16030534351145, -31.6044776119403),
        new Posicion(28.290076335877863, -28.470149253731343),
        new Posicion(-28.290076335877863, -28.470149253731343),
        new Posicion(11.16030534351145, -1.3059701492537314),
        new Posicion(-10.641221374045802, -0.7835820895522387),
        new Posicion(-27.251908396946565, 31.6044776119403),
        new Posicion(-10.641221374045802, 30.559701492537314),
        new Posicion(9.603053435114505, 28.992537313432837),
        new Posicion(25.69465648854962, 28.992537313432837)
    };
    Posicion alineacion5[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-11.16030534351145, -35.78358208955224),
        new Posicion(12.717557251908397, -35.26119402985075),
        new Posicion(28.290076335877863, -28.470149253731343),
        new Posicion(-28.290076335877863, -28.470149253731343),
        new Posicion(14.793893129770993, -18.544776119402986),
        new Posicion(-17.389312977099234, -19.58955223880597),
        new Posicion(-23.618320610687025, -0.7835820895522387),
        new Posicion(5.969465648854961, -5.485074626865671),
        new Posicion(0.2595419847328244, -0.26119402985074625),
        new Posicion(22.580152671755727, -1.3059701492537314)
    };
    Posicion alineacion6[] = new Posicion[]{
        new Posicion(0.2595419847328244, -50.41044776119403),
        new Posicion(-11.16030534351145, -35.78358208955224),
        new Posicion(12.717557251908397, -35.26119402985075),
        new Posicion(28.290076335877863, -28.470149253731343),
        new Posicion(-28.290076335877863, -28.470149253731343),
        new Posicion(14.793893129770993, -18.544776119402986),
        new Posicion(-17.389312977099234, -19.58955223880597),
        new Posicion(-23.618320610687025, -0.7835820895522387),
        new Posicion(6.4885496183206115, -6.529850746268657),
        new Posicion(-6.4885496183206115, -6.529850746268657),
        new Posicion(22.580152671755727, -1.3059701492537314)
    };

    class TacticaDetalleImpl implements TacticaDetalle {

        public String getNombre() {
            return "ElepanderEvo";
        }

        public String getPais() {
            return "España";
        }

        public String getEntrenador() {
            return "Señor Burns";
        }

        public Color getColorCamiseta() {
            return new Color(0, 0, 255);
        }

        public Color getColorPantalon() {
            return new Color(238, 238, 238);
        }

        public Color getColorFranja() {
            return new Color(102, 204, 255);
        }

        public Color getColorCalcetas() {
            return new Color(153, 204, 255);
        }

        public Color getColorPortero() {
            return new Color(255, 0, 255);
        }

        public EstiloUniforme getEstilo() {
            return EstiloUniforme.FRANJA_DIAGONAL;
        }

        public Color getColorCamiseta2() {
            return new Color(77, 137, 159);
        }

        public Color getColorPantalon2() {
            return new Color(11, 46, 184);
        }

        public Color getColorFranja2() {
            return new Color(244, 246, 55);
        }

        public Color getColorCalcetas2() {
            return new Color(52, 224, 161);
        }

        public Color getColorPortero2() {
            return new Color(78, 69, 117);
        }

        public EstiloUniforme getEstilo2() {
            return EstiloUniforme.FRANJA_HORIZONTAL;
        }

        class JugadorImpl implements JugadorDetalle {

            String nombre;
            int numero;
            Color piel, pelo;
            double velocidad, remate, presicion;
            boolean portero;
            Posicion posicion;

            public JugadorImpl(String nombre, int numero, Color piel, Color pelo,
                    double velocidad, double remate, double presicion, boolean portero) {
                this.nombre = nombre;
                this.numero = numero;
                this.piel = piel;
                this.pelo = pelo;
                this.velocidad = velocidad;
                this.remate = remate;
                this.presicion = presicion;
                this.portero = portero;
            }

            public String getNombre() {
                return nombre;
            }

            public Color getColorPiel() {
                return piel;
            }

            public Color getColorPelo() {
                return pelo;
            }

            public int getNumero() {
                return numero;
            }

            public boolean esPortero() {
                return portero;
            }

            public double getVelocidad() {
                return velocidad;
            }

            public double getRemate() {
                return remate;
            }

            public double getPresicion() {
                return presicion;
            }
        }

        public JugadorDetalle[] getJugadores() {
            return new JugadorDetalle[]{
                        new JugadorImpl("Juan", 1, new Color(255, 200, 150), new Color(50, 0, 0), 0.94d, 0.89d, 0.98d, true),
                        new JugadorImpl("Alvaro", 2, new Color(255, 200, 150), new Color(50, 0, 0), 0.9d, 0.89d, 0.89d, false),
                        new JugadorImpl("Alberto", 3, new Color(255, 200, 150), new Color(50, 0, 0), 0.84d, 0.85d, 0.85d, false),
                        new JugadorImpl("FranFerri", 4, new Color(255, 200, 150), new Color(50, 0, 0), 0.75d, 0.74d, 0.74d, false),
                        new JugadorImpl("Jose", 5, new Color(255, 200, 150), new Color(50, 0, 0), 0.78d, 0.78d, 0.79d, false),
                        new JugadorImpl("Roberto", 6, new Color(255, 200, 150), new Color(50, 0, 0), 0.82d, 0.83d, 0.84d, false),
                        new JugadorImpl("Alex", 7, new Color(255, 200, 150), new Color(50, 0, 0), 0.78d, 0.77d, 0.76d, false),
                        new JugadorImpl("Miguel", 8, new Color(255, 200, 150), new Color(50, 0, 0), 0.81d, 0.8d, 0.81d, false),
                        new JugadorImpl("Paco", 9, new Color(255, 200, 150), new Color(50, 0, 0), 0.82d, 0.83d, 0.85d, false),
                        new JugadorImpl("Ruben", 10, new Color(255, 200, 150), new Color(50, 0, 0), 0.85d, 0.85d, 0.85d, false),
                        new JugadorImpl("Angel", 11, new Color(255, 200, 150), new Color(50, 0, 0), 0.84d, 0.84d, 0.94d, false)
                    };
        }
    }
    TacticaDetalle detalle = new TacticaDetalleImpl();

    public TacticaDetalle getDetalle() {
        return detalle;
    }

    public Posicion[] getPosicionSaca(SituacionPartido sp) {
        return alineacion2;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
        return alineacion3;
    }
    public final static int NUM_JUGADORES = 11;
    public final static int DISTANCIA_ROBO_BALON = 6;

    public double distanciaRivalMasCercano(Posicion miPosicion, SituacionPartido sp) {
        final Posicion[] posicionRivales = sp.rivales();
        double minimaDistancia = 500;
        double distancia;
        for (Posicion posicionRival : posicionRivales) {
            distancia = miPosicion.distancia(posicionRival);
            if (minimaDistancia > distancia) {
                minimaDistancia = distancia;
            }
        }
        return minimaDistancia;
    }

    public Posicion posicionRivalMasCercano(Posicion miPosicion, SituacionPartido sp) {
        final Posicion[] posicionRivales = sp.rivales();
        double minimaDistancia = 500;
        double distancia;
        Posicion posicionRivalMasCercano = new Posicion();
        for (Posicion posicionRival : posicionRivales) {
            distancia = miPosicion.distancia(posicionRival);
            if (minimaDistancia > distancia) {
                minimaDistancia = distancia;
                posicionRivalMasCercano = posicionRival;
            }
        }
        return posicionRivalMasCercano;
    }

    /**
     *
     * @param miPosicion
     * @param sp
     * @param nivel 0 busca el jugador más cercano, 1 busca el siguiente más cercano
     * @return
     */
    public Posicion posicionRivalMasNivelCercania(Posicion miPosicion, SituacionPartido sp, int nivel) {
        final Posicion[] posicionRivales = sp.rivales();
        List<Posicion> arrayPosicionesJugadoresRivalesPorCercania = new ArrayList();
        double minimaDistancia = 500;
        double distancia;
        Posicion posicionRivalMasCercano = new Posicion();
        Posicion posicionRivalMasCercano2 = new Posicion();
        for (Posicion posicionRival : posicionRivales) {
            distancia = miPosicion.distancia(posicionRival);
            if (minimaDistancia > distancia) {
                minimaDistancia = distancia;
                posicionRivalMasCercano2.setPosicion(posicionRivalMasCercano.getX(), posicionRivalMasCercano.getY());
                posicionRivalMasCercano = posicionRival;
                arrayPosicionesJugadoresRivalesPorCercania.add(posicionRivalMasCercano);
            }
        }
        return arrayPosicionesJugadoresRivalesPorCercania.get(nivel);
    }

    public int[] obtenerDelanterosRivalesCubiertos(SituacionPartido sp) {

        int[] listaJugadoresCubiertos = new int[11];
        inicializarListaACero(listaJugadoresCubiertos);

        final Posicion[] posicionmisJugadores = sp.misJugadores();
        final Posicion[] posicionRivales = sp.rivales();

        JugadorDetalle[] detalleJugadoresRivales = sp.detalleJugadoresRivales();
        for (JugadorDetalle detalleJugadorRival : detalleJugadoresRivales) {
            int numero = detalleJugadorRival.getNumero();
            if (detalleJugadorRival.esPortero()) {
                if (numero >= 0 && numero < 11) {
                    listaJugadoresCubiertos[numero] = 1;//Error detalleJugadorRival.getNumero() puede ser 20
                }
            } else if (numero > 0 && numero < 11 && rivalEstaCubierto(posicionRivales[numero - 1], posicionmisJugadores)) {
                listaJugadoresCubiertos[numero - 1]++;//Error detalleJugadorRival.getNumero() puede ser 20
            }
        }
        return listaJugadoresCubiertos;
    }

    private void inicializarListaACero(int[] listaJugadoresCubiertos) {
        for (int i = 0; i < NUM_JUGADORES; i++) {
            listaJugadoresCubiertos[i] = 0;
        }
    }

    private boolean rivalEstaCubierto(Posicion posicionRival, Posicion[] posicionMisJugadores) {
        for (Posicion miPosicion : posicionMisJugadores) {
            if ((posicionRival.getX() - DISTANCIA_ROBO_BALON <= miPosicion.getX())
                    && (miPosicion.getX() <= posicionRival.getX() + DISTANCIA_ROBO_BALON)
                    && (posicionRival.getY() - DISTANCIA_ROBO_BALON <= miPosicion.getY())
                    && (miPosicion.getY() <= posicionRival.getY() + DISTANCIA_ROBO_BALON)) {
                return true;
            }
        }
        return false;
    }

    public boolean rivalEstaCubiertoPorMi(Posicion posicionRival, Posicion miPosicion) {
        if ((posicionRival.getX() - Constantes.DISTANCIA_CONTROL_BALON <= miPosicion.getX())
                && (miPosicion.getX() <= posicionRival.getX() + Constantes.DISTANCIA_CONTROL_BALON)
                && (posicionRival.getY() - Constantes.DISTANCIA_CONTROL_BALON <= miPosicion.getY())
                && (miPosicion.getY() <= posicionRival.getY() + Constantes.DISTANCIA_CONTROL_BALON)) {
            return true;
        }
        return false;
    }

    public boolean rivalEstaCubiertoSoloPorMi(Posicion posicionRival, Posicion[] misPosiciones, int i) {
        int jugadoresCubriendo = 0;
        boolean yoCubro = false;
        for (int jugador = 0; jugador < misPosiciones.length; jugador++) {
            if (rivalEstaCubiertoPorMi(posicionRival, misPosiciones[i])) {
                if (jugador == i) {
                    yoCubro = true;
                }
                jugadoresCubriendo++;
            }
            if (jugadoresCubriendo > 1) {
                return false;
            }
        }
        return jugadoresCubriendo == 1 && yoCubro;
    }

    public boolean rivalEstaCubiertoPorVariosIncluidoYo(Posicion posicionRival, Posicion[] misPosiciones, int i) {
        int jugadoresCubriendo = 0;
        boolean yoCubro = false;
        for (int jugador = 0; jugador < misPosiciones.length; jugador++) {
            if (rivalEstaCubiertoPorMi(posicionRival, misPosiciones[i])) {
                if (jugador == i) {
                    yoCubro = true;
                }
                jugadoresCubriendo++;
            }
            if (jugadoresCubriendo > 1 && yoCubro) {
                return true;
            }
        }
        return false;
    }

    /**
     * Devuelve true si he sobrepasado la vertical a 30 metros de la porteria
     * @param miPosicion
     * @param sp
     * @return
     */
    public boolean estoyEnDisposicionDeRematar(Posicion miPosicion, SituacionPartido sp) {
        int numeroPorteroRival = numeroPorteroRival(sp);
        if ((sp.rivales()[numeroPorteroRival].getY() - 30 <= miPosicion.getY())
                && (miPosicion.getY() <= sp.rivales()[numeroPorteroRival].getY() + 30)) {
            return true;
        }
        return false;

    }

    /**
     * Devuelve el numero del portero rival
     * @param sp
     * @return
     */
    public int numeroPorteroRival(SituacionPartido sp) {
        int numeroPorteroRival = 0;
        for (int i = 0; i < sp.detalleJugadoresRivales().length; i++) {
            if (sp.detalleJugadoresRivales()[i].esPortero()) {
                numeroPorteroRival = i;
            }
        }
        return numeroPorteroRival;
    }

    public int buscarJugadorOptimo(int i, SituacionPartido sp) {

        //jugador mas cercano adelantado que el
        Random r = new Random();
        return (r.nextInt(5)) + 6;
    }

    public boolean estoyCubierto(Posicion miPosicion, SituacionPartido sp) {
        for (int i = 1; i <= NUM_JUGADORES; i++) {
            if (rivalEstaCubierto(miPosicion, sp.rivales())) {
                return true;
            }
        }
        return false;
    }

    public Posicion getTrayectoriaPorteriaContraria(Posicion miPosicion, SituacionPartido sp) {
        int numeroPorteroRival = numeroPorteroRival(sp);
        return Posicion.media(sp.rivales()[numeroPorteroRival], miPosicion);
    }
    LinkedList<Comando> comandos = new LinkedList<Comando>();

    @Override
    public List<Comando> ejecutar(SituacionPartido sp) {

        int[] indiceRivalesCubiertos = obtenerDelanterosRivalesCubiertos(sp);
        List rivalesCubiertos = new ArrayList();
        List nuestrosCubriendo = new ArrayList();
        JugadorDetalle[] misJugadoresDetalle = sp.detalleMisJugadores();
        comandos.clear();
        //Obtiene las posiciones de tus jugadores
        Posicion[] posicionJugadores = sp.misJugadores();
        for (int i = 0; i < NUM_JUGADORES; i++) {
            //Ordena a cada jugador que se ubique segun la alineacion1
            if (misJugadoresDetalle[i].esPortero()) {
                comandos.add(new ComandoIrA(i, alineacion1[i]));
            }
            //Soy defensa
            if ((i <= 4) && (i > 1)) {
                int j = 0;
                boolean cubriendoRival = false;
                for (Posicion rival : sp.rivales()) {

                    // si el rival está cubierto solo por mí
                    if (rivalEstaCubiertoSoloPorMi(rival, posicionJugadores, i)) {
                        // sigo cubriendole ---- moverme a su posicion
                        rivalesCubiertos.add(sp.detalleJugadoresRivales()[j]);
                        nuestrosCubriendo.add(sp.detalleMisJugadores()[i]);
                        cubriendoRival = true;
                        comandos.add(new ComandoIrA(i, new Posicion(rival.getX(), (rival.getY() + 10))));
                    } // si el rival está cubierto por mí y por más jugadores míos
                    else if (rivalEstaCubiertoPorVariosIncluidoYo(rival, posicionJugadores, i)
                            && !rivalesCubiertos.contains(rival)) {
                        // ver si soy el que peor cubre y cubrirle (el primero en evaluar)
                        rivalesCubiertos.add(rival);
                        nuestrosCubriendo.add(sp.detalleMisJugadores()[i]);
                        cubriendoRival = true;
                        comandos.add(new ComandoIrA(i, new Posicion(rival.getX(), (rival.getY() + 10))));

                    }
                    j++;
                }
                // buscar contrario no cubierto mas cercano --- y me voy a el
                // marco a ese jugador rival como ya cubierto
                if (!cubriendoRival) {
                    comandos.add(new ComandoIrA(i, posicionRivalMasCercano(posicionJugadores[i], sp)));
                }
            } else {
                comandos.add(new ComandoIrA(i, alineacion1[i]));
            }
        }
        if (!sp.sacaRival()) {
            int[] recuperadores = sp.getRecuperacionBalon();
            if (recuperadores.length > 1) {
                double[] posRecuperacion = sp.getTrayectoria(recuperadores[0]);
                for (int i = 1; i < recuperadores.length; i++) {
                    comandos.add(new ComandoIrA(recuperadores[1], //TODO: abarranco: va solo 1 de los jugadores, el mas cercano
                            new Posicion(posRecuperacion[0], posRecuperacion[1])));
                }
            }
        }
        Random r = new Random();
        for (int i : sp.puedenRematar()) {
            //Si el jugador es de indice 8 o 10
            if (i == 0) { //Soy el portero
                comandos.add(new ComandoGolpearBalon(i, alineacion1[1], 1, 12 + Constantes.ANGULO_VERTICAL_MAX));
            }
            if (estoyEnDisposicionDeRematar(posicionJugadores[i], sp)) {
                comandos.add(new ComandoGolpearBalon(i, Constantes.centroArcoSup, 1, 12 + r.nextInt(6)));
            } else {
                int jugadorDestino;
                if (estoyCubierto(posicionJugadores[i], sp) || i == 0) {
                    jugadorDestino = buscarJugadorOptimo(i, sp);
                    comandos.add(new ComandoGolpearBalon(i, posicionJugadores[jugadorDestino], 1, 15));
                } else {
                    Posicion trayectoriaPorteriaContraria = getTrayectoriaPorteriaContraria(posicionJugadores[i], sp);
                    comandos.add(new ComandoGolpearBalon(i, trayectoriaPorteriaContraria, 0.42, false));

                }

            }
        }

        Posicion trayectoriaParaJugador6 = getTrayectoriaPorteriaContraria(posicionJugadores[5], sp);
        comandos.add(new ComandoIrA(6, trayectoriaParaJugador6));
        Posicion trayectoriaParaJugador4 = getTrayectoriaPorteriaContraria(sp.balon(), sp);
        comandos.add(new ComandoIrA(4, trayectoriaParaJugador4));
        return comandos;
    }
}
